package ngat.oss;

import java.util.*;
import java.io.*;
import ngat.util.*;
import ngat.phase2.*;
import ngat.astrometry.*;

public class ChargingModel {

    private double offsetCost;
    private double slewCost;
    private double configCost;
    private double readoutCost;

    public ChargingModel() {

    }

    public void configure(File file) throws Exception {
	
	ConfigurationProperties config = new ConfigurationProperties();
	config.load(new FileInputStream(file));

	configure(config);

    }


    public void configure(ConfigurationProperties config) throws Exception {

	offsetCost  = config.getDoubleValue("offset.cost");
	slewCost    = config.getDoubleValue("slew.cost");
	configCost  = config.getDoubleValue("config.cost");
	readoutCost = config.getDoubleValue("readout.cost");

	ExecutionCosting.slewRate    = slewCost;
	ExecutionCosting.offsetRate  = offsetCost;
	ExecutionCosting.configRate  = configCost;
	ExecutionCosting.readoutRate = readoutCost;

    }

    /** Returns the cost for executing the group at time.*/
    public ExecutionCosting calculateCost(Group group, long time) {
	
        int countObs       = 0; // counts obs.
        int countSlews     = 1; // counts distinct source moves - include initial slew onto (first) target
	int countOffsets   = 0; // counts mosaic offsets
	int countExposures = 0; // counts exposures
	int countConfigs   = 0; // counts config changes

	double sumExpose  = 0.0;

        Observation observation = null;
        Source      source      = null;
        Source  prevSource      = null;
        Position    target      = null;
        Position    prevTarget  = null;
	InstrumentConfig instConfig = null;
        InstrumentConfig prevConfig = null;

        // check for sequencing here and create it if it doesnt exist...
        Vector v = null;
        v = group.getSequence();
        System.err.println("GT::CrtTaskList::Group sequence is: "+v);
        if (v == null || v.size() == 0) {
            v = new Vector();
            Iterator it = group.listAllObservations();
            while (it.hasNext()) {
                observation = (Observation)it.next();
                v.add(observation.getName());
            }
        }

        int nseq = v.size();

        Iterator is = v.iterator();
        while (is.hasNext()) {
            String obsName = (String)is.next();
            observation = group.findObservation(obsName);

            countObs++;

            instConfig = observation.getInstrumentConfig();

            source      = observation.getSource();
            target      = source.getPosition();

            // If this is NOT first obs. There IS a previous source.
            if (countObs != 1) {
                if (source != prevSource) {
                    // New source. Add Slew time
		    countSlews++;
		}

		if (! (instConfig.sameAs(prevConfig))) {
		    // New config. Add cfg time
		    countConfigs++;
		}
            }
            prevSource = source;
            prevTarget = target;
	    prevConfig = instConfig;

            // Add up all the contributions to this Obo's time.

            // Mosaics.
            int mosaic = 1;
            switch (observation.getMosaic().getPattern()) {
            case Mosaic.ARRAY:
                mosaic = observation.getMosaic().getCellsRA()*observation.getMosaic().getCellsDec();
                break;
            case Mosaic.SINGLE:
                mosaic = 1;
                break;
            case Mosaic.VERTICAL:
            case Mosaic.HORIZONTAL:
            case Mosaic.SLOPE_UP:
            case Mosaic.SLOPE_DOWN:
                mosaic = 3;
                break;
            case Mosaic.CROSS:
            case Mosaic.X:
                mosaic = 5;
                break;
            case Mosaic.HOLE:
                mosaic = 8;
                break;
            case Mosaic.GRID:
                mosaic = 9;
                break;
            default:
                mosaic = 1;
            }

	    // dont count the first one
	  
            // Multruns.
            int multruns = observation.getNumRuns();

	    countOffsets += (mosaic-1);	   
	    countExposures += multruns*mosaic;
	    
	    sumExpose  += mosaic *multruns*(observation.getExposeTime()/1000); // convert msec to sec

        } // per observation.
	
	double totalCost = countOffsets*offsetCost + 
	    countExposures*readoutCost + 
	    sumExpose +
	    countConfigs*configCost + 
	    countSlews*slewCost;

	ExecutionCosting cost = new ExecutionCosting();
	
	cost.nSlew   = countSlews;
	cost.nOffset = countOffsets;
	cost.nConfig = countConfigs;
	cost.nExpose = countExposures;
	cost.totalExpose = sumExpose;

	return cost;

    }

}
